package cloud

import (
	"fmt"
	"strings"
	"time"

	"gitee.com/rw555/fdsmastergo/pkg/logger"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"go.uber.org/zap"
)

// MQTTClient MQTT客户端
type MQTTClient struct {
	systemConfig map[string]interface{}
	client       mqtt.Client
	handlers     map[string]mqtt.MessageHandler
}

// NewMQTTClient 创建MQTT客户端
func NewMQTTClient(systemConfig map[string]interface{}) (*MQTTClient, error) {
	// 创建MQTT客户端选项
	opts := mqtt.NewClientOptions()
	opts.AddBroker(systemConfig["mqtt.broker_address"].(string))
	opts.SetClientID(systemConfig["mqtt.client_id"].(string))
	if username, ok := systemConfig["mqtt.username"].(string); ok && username != "" {
		opts.SetUsername(username)
		opts.SetPassword(systemConfig["mqtt.password"].(string))
	}
	opts.SetKeepAlive(time.Duration(systemConfig["mqtt.keep_alive"].(float64)) * time.Second)
	opts.SetCleanSession(systemConfig["mqtt.clean_session"].(bool))
	opts.SetConnectTimeout(time.Duration(systemConfig["mqtt.connect_timeout"].(float64)) * time.Second)
	opts.SetAutoReconnect(true)
	opts.SetMaxReconnectInterval(1 * time.Minute)

	// 创建MQTT客户端
	client := mqtt.NewClient(opts)

	return &MQTTClient{
		systemConfig: systemConfig,
		client:       client,
		handlers:     make(map[string]mqtt.MessageHandler),
	}, nil
}

// formatTopic 格式化主题字符串，替换变量
func formatTopic(topic string, params map[string]string) string {
	// 替换 {device_number}
	if deviceNumber, ok := params["device_number"]; ok {
		topic = strings.Replace(topic, "{device_number}", deviceNumber, -1)
	}

	// 替换 {message_id}
	if messageId, ok := params["message_id"]; ok {
		topic = strings.Replace(topic, "{message_id}", messageId, -1)
	}

	return topic
}

// generateMessageId 生成消息ID（毫秒时间戳后7位）
func generateMessageId() string {
	timestamp := time.Now().UnixNano() / 1e6 // 转换为毫秒
	messageId := fmt.Sprintf("%07d", timestamp%10000000)
	return messageId
}

// subscribe 订阅主题（内部使用）
func (c *MQTTClient) subscribe(topic string, handler mqtt.MessageHandler) error {
	if c.client == nil {
		return fmt.Errorf("MQTT客户端未初始化")
	}

	params := map[string]string{
		"device_number": c.systemConfig["mqtt.device_number"].(string),
	}

	formattedTopic := formatTopic(topic, params)

	if token := c.client.Subscribe(formattedTopic, byte(c.systemConfig["mqtt.default_qos"].(float64)), handler); token.Wait() && token.Error() != nil {
		return fmt.Errorf("订阅主题失败: %w", token.Error())
	}

	logger.SystemDebug("MQTT主题订阅成功", zap.String("topic", formattedTopic))
	return nil
}

// unsubscribe 取消订阅主题（内部使用）
func (c *MQTTClient) unsubscribe(topic string) error {
	if c.client == nil {
		return fmt.Errorf("MQTT客户端未初始化")
	}

	if token := c.client.Unsubscribe(topic); token.Wait() && token.Error() != nil {
		return fmt.Errorf("取消订阅失败: %w", token.Error())
	}

	logger.SystemDebug("MQTT主题取消订阅成功", zap.String("topic", topic))
	return nil
}

// RegisterHandler 注册主题处理函数
func (c *MQTTClient) RegisterHandler(topic string, handler mqtt.MessageHandler) {
	c.handlers[topic] = handler

	// 如果已连接，立即订阅
	if c.client != nil && c.client.IsConnected() {
		if err := c.subscribe(topic, handler); err != nil {
			logger.SystemError("订阅主题失败", zap.String("topic", topic), zap.Error(err))
		}
	}

	logger.SystemInfo("注册主题处理函数", zap.String("topic", topic))
}

// UnregisterHandler 取消注册主题处理函数
func (c *MQTTClient) UnregisterHandler(topic string) {
	delete(c.handlers, topic)

	// 如果已连接，立即取消订阅
	if c.client != nil && c.client.IsConnected() {
		if err := c.unsubscribe(topic); err != nil {
			logger.SystemError("取消订阅主题失败", zap.String("topic", topic), zap.Error(err))
		}
	}

	logger.SystemInfo("取消注册主题处理函数", zap.String("topic", topic))
}

// Connect 连接MQTT服务器
func (c *MQTTClient) Connect() error {
	logger.SystemInfo("连接MQTT服务器", zap.Any("config", c.systemConfig))

	opts := mqtt.NewClientOptions()
	opts.AddBroker(c.systemConfig["mqtt.broker_address"].(string))
	opts.SetClientID(c.systemConfig["mqtt.client_id"].(string))
	if username, ok := c.systemConfig["mqtt.username"].(string); ok && username != "" {
		opts.SetUsername(username)
		opts.SetPassword(c.systemConfig["mqtt.password"].(string))
	}

	// 设置连接选项
	opts.SetKeepAlive(time.Duration(c.systemConfig["mqtt.keep_alive"].(float64)) * time.Second)
	opts.SetCleanSession(c.systemConfig["mqtt.clean_session"].(bool))
	opts.SetConnectTimeout(time.Duration(c.systemConfig["mqtt.connect_timeout"].(float64)) * time.Second)
	opts.SetAutoReconnect(true)
	opts.SetMaxReconnectInterval(time.Second * 10)

	// 设置连接成功回调
	opts.SetOnConnectHandler(func(client mqtt.Client) {
		logger.SystemInfo("MQTT已连接到服务器",
			zap.String("broker", c.systemConfig["mqtt.broker_address"].(string)),
			zap.String("client_id", c.systemConfig["mqtt.client_id"].(string)))

		// 重新订阅所有主题
		for topic, handler := range c.handlers {
			if err := c.subscribe(topic, handler); err != nil {
				logger.SystemError("重新订阅主题失败", zap.String("topic", topic), zap.Error(err))
			}
		}
	})

	// 设置连接断开回调
	opts.SetConnectionLostHandler(func(client mqtt.Client, err error) {
		logger.SystemError("MQTT连接丢失",
			zap.String("broker", c.systemConfig["mqtt.broker_address"].(string)),
			zap.String("client_id", c.systemConfig["mqtt.client_id"].(string)),
			zap.Error(err))
	})

	// 创建并连接新的客户端实例
	newClient := mqtt.NewClient(opts)
	if token := newClient.Connect(); token.Wait() && token.Error() != nil {
		return fmt.Errorf("连接MQTT服务器失败: %w", token.Error())
	}

	c.client = newClient
	return nil
}

// Disconnect 断开MQTT连接
func (c *MQTTClient) Disconnect() {
	if c.client != nil {
		c.client.Disconnect(250)
		c.client = nil
		logger.SystemInfo("MQTT连接已断开")
	}
}

// IsConnected 检查是否已连接
func (c *MQTTClient) IsConnected() bool {
	return c.client != nil && c.client.IsConnected()
}

// GetBrokerURL 获取MQTT代理地址
func (c *MQTTClient) GetBrokerURL() string {
	if c.systemConfig == nil {
		return ""
	}

	broker, ok := c.systemConfig["mqtt.broker_address"].(string)
	if !ok {
		return ""
	}

	return broker
}

// GetClientID 获取MQTT客户端ID
func (c *MQTTClient) GetClientID() string {
	if c.systemConfig == nil {
		return ""
	}

	clientID, ok := c.systemConfig["mqtt.client_id"].(string)
	if !ok {
		return ""
	}

	return clientID
}

// Publish 发布消息
func (c *MQTTClient) Publish(topic string, payload interface{}) error {
	if c.client == nil {
		return fmt.Errorf("MQTT客户端未初始化")
	}

	params := map[string]string{
		"message_id":    generateMessageId(),
		"device_number": c.systemConfig["mqtt.device_number"].(string),
	}

	formattedTopic := formatTopic(topic, params)

	if token := c.client.Publish(formattedTopic, byte(c.systemConfig["mqtt.default_qos"].(float64)),
		c.systemConfig["mqtt.default_retained"].(bool), payload); token.Wait() && token.Error() != nil {
		return fmt.Errorf("发布消息失败: %w", token.Error())
	}

	logger.SystemDebug("MQTT消息发布成功",
		zap.String("topic", formattedTopic),
		zap.Any("payload", payload))
	return nil
}
